//|||||||||||||||||||||||||||||||||||||||||||||||

#include "EditorState.h"

#include "GameState.h"

//|||||||||||||||||||||||||||||||||||||||||||||||

using namespace Ogre;

//|||||||||||||||||||||||||||||||||||||||||||||||

EditorState::EditorState()
{
    m_MoveSpeed		= 0.1f;
    m_RotateSpeed	= 0.3f;

    m_bLMouseDown       = false;
    m_bRMouseDown       = false;
    m_bQuit             = false;
    m_bSettingsMode     = false;

    m_pDetailsPanel	= 0;

    m_gameManager = 0;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void EditorState::enter()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering EditorState...");

    m_pSceneMgr = OgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "GameSceneMgr");
    m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));

    m_pRSQ = m_pSceneMgr->createRayQuery(Ray());
    m_pRSQ->setQueryMask(QUERY_BLOCK);

    m_pCamera = m_pSceneMgr->createCamera("EditorCamera");
    m_pCamera->setPosition(Vector3(0, 10, -5));
    m_pCamera->lookAt(Vector3(0, 0, 0));
    m_pCamera->setNearClipDistance(0.01);


    m_pCamera->setAspectRatio(Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualWidth()) /
                              Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));

    OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
    m_pCurrentObject = 0;

    buildGUI();

    createScene();

    GameManager::getInstance()->init();
//    GameManager::getInstance()->createCharacter("player",Ogre::Vector2(10,10));




}

bool EditorState::pause()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Pausing EditorState...");

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void EditorState::resume()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Resuming EditorState...");

    buildGUI();

    OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
    m_bQuit = false;
}

void EditorState::exit()
{

    GameManager::getInstance()->clear();




    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Leaving EditorState...");

    m_pSceneMgr->destroyCamera(m_pCamera);
    m_pSceneMgr->destroyQuery(m_pRSQ);
    if(m_pSceneMgr)
        OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);
}

void EditorState::createScene()
{
    m_pSceneMgr->createLight("Light")->setPosition(75,75,75);

//   DotSceneLoader* pDotSceneLoader = new DotSceneLoader();
//   pDotSceneLoader->parseDotScene("CubeScene.xml", "General", m_pSceneMgr, m_pSceneMgr->getRootSceneNode());
//   delete pDotSceneLoader;
    /*
        m_pSceneMgr->getEntity("Cube01")->setQueryFlags(CUBE_MASK);
        m_pSceneMgr->getEntity("Cube02")->setQueryFlags(CUBE_MASK);
        m_pSceneMgr->getEntity("Cube03")->setQueryFlags(CUBE_MASK);*/
    /*

    m_pOgreHeadEntity = m_pSceneMgr->createEntity("CubeT", "ogrehead.mesh");
    m_pOgreHeadEntity->setQueryFlags(OGRE_HEAD_MASK);
    m_pOgreHeadNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("CubeNodeT");
    m_pOgreHeadNode->attachObject(m_pOgreHeadEntity);
    m_pOgreHeadNode->setPosition(Vector3(0, 0, -25));

    m_pOgreHeadMat = m_pOgreHeadEntity->getSubEntity(1)->getMaterial();
    m_pOgreHeadMatHigh = m_pOgreHeadMat->clone("OgreHeadMatHigh");
    m_pOgreHeadMatHigh->getTechnique(0)->getPass(0)->setAmbient(1, 0, 0);
    m_pOgreHeadMatHigh->getTechnique(0)->getPass(0)->setDiffuse(1, 0, 0, 0);
    */

}

bool EditorState::keyPressed(const OIS::KeyEvent &keyEventRef)
{
    if(m_bSettingsMode == true)
    {
        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_S))
        {
            OgreBites::SelectMenu* pMenu = (OgreBites::SelectMenu*)OgreFramework::getSingletonPtr()->m_pTrayMgr->getWidget("ChatModeSelMenu");
            if(pMenu->getSelectionIndex() + 1 < (int)pMenu->getNumItems())
                pMenu->selectItem(pMenu->getSelectionIndex() + 1);
        }

        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_W))
        {
            OgreBites::SelectMenu* pMenu = (OgreBites::SelectMenu*)OgreFramework::getSingletonPtr()->m_pTrayMgr->getWidget("ChatModeSelMenu");
            if(pMenu->getSelectionIndex() - 1 >= 0)
                pMenu->selectItem(pMenu->getSelectionIndex() - 1);
        }
    }

    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
    {
        pushAppState(findByName("PauseState"));
        return true;
    }

    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_I))
    {
        if(m_pDetailsPanel->getTrayLocation() == OgreBites::TL_NONE)
        {
            OgreFramework::getSingletonPtr()->m_pTrayMgr->moveWidgetToTray(m_pDetailsPanel, OgreBites::TL_TOPLEFT, 0);
            m_pDetailsPanel->show();
        }
        else
        {
            OgreFramework::getSingletonPtr()->m_pTrayMgr->removeWidgetFromTray(m_pDetailsPanel);
            m_pDetailsPanel->hide();
        }
    }

    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_TAB))
    {
        m_bSettingsMode = !m_bSettingsMode;
        return true;
    }

    if(m_bSettingsMode && OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_RETURN) ||
            OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_NUMPADENTER))
    {
    }

    if(!m_bSettingsMode || (m_bSettingsMode && !OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_O)))
        OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool EditorState::keyReleased(const OIS::KeyEvent &keyEventRef)
{
    OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
    return true;
}


bool EditorState::mouseMoved(const OIS::MouseEvent &evt)
{

    //TODO : bug quand la souris ne pointe pas sur un block
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;

    if(m_bLMouseDown)
    {



        Ogre::Ray mouseRay = m_pCamera->getCameraToViewportRay(OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().X.abs / float(evt.state.width),
                             OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().Y.abs / float(evt.state.height));
        m_pRSQ->setRay(mouseRay);
        m_pRSQ->setSortByDistance(true);

        Ogre::RaySceneQueryResult &result = m_pRSQ->execute();
        Ogre::RaySceneQueryResult::iterator itr;

        for(itr = result.begin(); itr != result.end(); itr++)
        {

            if(itr->movable)
            {
                m_pCurrentObject = m_pSceneMgr->getEntity(itr->movable->getName())->getParentSceneNode();
            }
        }

        std::pair<bool,Ogre::Real> pair;
        pair = mouseRay.intersects(Ogre::Plane(Ogre::Vector3::UNIT_Y,0.0));
        Ogre::Vector2 posAtGround = Ogre::Vector2(mouseRay.getPoint(pair.second).x,mouseRay.getPoint(pair.second).z);

        if(m_pCurrentObject)
        {
            Ogre::Vector2 p = Ogre::Vector2(m_pCurrentObject->getPosition().x,m_pCurrentObject->getPosition().z);
            if (!m_currentBlock.empty())
                GameManager::getInstance()->getLevelMgrPtr()->setBlockAt("../data/block/" + m_currentBlock,p.x,p.y);

        }

    }

    return true;

}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool EditorState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;

    if(id == OIS::MB_Left)
    {
        onLeftPressed(evt);
        m_bLMouseDown = true;
    }
    else if(id == OIS::MB_Right)
    {
        onRightPressed(evt);
        m_bRMouseDown = true;
    }

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool EditorState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;

    if(id == OIS::MB_Left)
    {
        m_bLMouseDown = false;
    }
    else if(id == OIS::MB_Right)
    {
        m_bRMouseDown = false;
    }

    return true;
}

void EditorState::onLeftPressed(const OIS::MouseEvent &evt)
{
    /* if(m_pCurrentObject)
     {
         m_pCurrentObject->showBoundingBox(false);

     }*/

    Ogre::Ray mouseRay = m_pCamera->getCameraToViewportRay(OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().X.abs / float(evt.state.width),
                         OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().Y.abs / float(evt.state.height));
    m_pRSQ->setRay(mouseRay);
    m_pRSQ->setSortByDistance(true);

    Ogre::RaySceneQueryResult &result = m_pRSQ->execute();
    Ogre::RaySceneQueryResult::iterator itr;



    for(itr = result.begin(); itr != result.end(); itr++)
    {

        if(itr->movable)
        {


            OgreFramework::getSingletonPtr()->m_pLog->logMessage("MovableName: " + itr->movable->getName());
            m_pCurrentObject = m_pSceneMgr->getEntity(itr->movable->getName())->getParentSceneNode();
            // m_pCurrentObject->showBoundingBox(true);

            break;
        }
    }
    std::pair<bool,Ogre::Real> pair;

    pair = mouseRay.intersects(Ogre::Plane(Ogre::Vector3::UNIT_Y,0.0));
    Ogre::Vector2 posAtGround = Ogre::Vector2(mouseRay.getPoint(pair.second).x,mouseRay.getPoint(pair.second).z);


    if(m_pCurrentObject)
    {
        Ogre::Vector2 p = Ogre::Vector2(m_pCurrentObject->getPosition().x,m_pCurrentObject->getPosition().z);


        if (!m_currentBlock.empty())
            GameManager::getInstance()->getLevelMgrPtr()->setBlockAt("../data/block/" + m_currentBlock,p.x,p.y);


        m_pDetailsPanel->setParamValue(0, Ogre::StringConverter::toString(p.x));
        m_pDetailsPanel->setParamValue(1, Ogre::StringConverter::toString(p.y));

        if (GameManager::getInstance()->getLevelMgrPtr()->isBlockCrossable(p.x,p.y))
        {
            m_pDetailsPanel->setParamValue(2, "Crossable");
            //GameManager::getInstance()->getObjectMgrPtr()->giveOrderToGoTo(posAtGround);
        }
        else
        {
            m_pDetailsPanel->setParamValue(2, "Non Crossable");
        }
    }
}

void EditorState::onRightPressed(const OIS::MouseEvent &evt)
{



}

void EditorState::moveCamera()
{
  //  m_pCamera->moveRelative(m_TranslateVector);
}

void EditorState::getInput()
{

//TODO class camera pour gerer tout cela mieux : bug quand la camera n'est plus au dessus du terrain
    m_TranslateVector = Vector3::ZERO;
    float u=0.1;

    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_LEFT))
        m_TranslateVector += Ogre::Vector3(-u,0,0);
    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_RIGHT))
        m_TranslateVector += Ogre::Vector3(u,0,0);
    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_UP))
        m_TranslateVector += Ogre::Vector3(0,u,-u/2.0);
    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_DOWN))
        m_TranslateVector += Ogre::Vector3(0,-u,-u/2.0);



}

void EditorState::update(double timeSinceLastFrame)
{
    m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
    OgreFramework::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);

    if(m_bQuit == true)
    {
        popAppState();
        return;
    }

    if(!OgreFramework::getSingletonPtr()->m_pTrayMgr->isDialogVisible())
    {
        if(m_pDetailsPanel->isVisible())
        {

            /*
                        if(m_bSettingsMode)
                            m_pDetailsPanel->setParamValue(2, "Buffered Input");
                        else
                            m_pDetailsPanel->setParamValue(2, "Un-Buffered Input");*/
        }
    }

    m_MoveScale = m_MoveSpeed   * timeSinceLastFrame;
    m_RotScale  = m_RotateSpeed * timeSinceLastFrame;

    m_TranslateVector = Vector3::ZERO;

    getInput();
    moveCamera();

    GameManager::getInstance()->update(timeSinceLastFrame);
}

void EditorState::buildGUI()
{
    OgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);

    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOP, "EditorLbl", "Editor mode", 250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();

    Ogre::StringVector items;
    items.push_back("X");
    items.push_back("Y");

    items.push_back("Mode");

    m_pDetailsPanel = OgreFramework::getSingletonPtr()->m_pTrayMgr->createParamsPanel(OgreBites::TL_TOPLEFT, "DetailsPanel", 200, items);

    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_BOTTOMRIGHT, "EditorMenuLbl", "Menu", 100);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "NewBtn", "New",100);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "RandomBtn", "Random", 100);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "SaveBtn", "Save", 100);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "LoadBtn", "Load", 100);
//OgreFramework::getSingletonPtr()->m_pTrayMgr->setWidgetPadding(3);
//OgreFramework::getSingletonPtr()->m_pTrayMgr->setTrayPadding(12);
    // m_pDetailsPanel->show();
    /*
        Ogre::String infoText = "[TAB] - Switch input mode\n\n[W] - Forward / Mode up\n[S] - Backwards/ Mode down\n[A] - Left\n";
        infoText.append("[D] - Right\n\nPress [SHIFT] to move faster\n\n[O] - Toggle FPS / logo\n");
        infoText.append("[Print] - Take screenshot\n\n[ESC] - Exit");
        OgreFramework::getSingletonPtr()->m_pTrayMgr->createTextBox(OgreBites::TL_RIGHT, "InfoPanel", infoText, 300, 220);*/
/*
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOPRIGHT, "EditorChooseObjectMenuLbl", "Choose...", 250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createCheckBox(OgreBites::TL_TOPRIGHT, "BlockBtn", "Block",250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "BuildingBtn", "Building", 250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "CharacterBtn", "Character", 250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "DecorBtn", "Decor", 250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "ItemBtn", "Item", 250);
    */

    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOPRIGHT, "ChooseLbl", "Choose object :", 250);
    Ogre::StringVector items2;
    items2.push_back("Block");
    items2.push_back("Building");
    items2.push_back("Item");
    items2.push_back("Character");
    items2.push_back("Decor");
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLongSelectMenu(OgreBites::TL_TOPRIGHT, "ChooseObjectMenu","Object", 200,6, items2);

    OgreFramework::getSingletonPtr()->m_pTrayMgr->SdkTrayManager::createSeparator(OgreBites::TL_TOPRIGHT,"ChooseMenuSeparator",250);

    StringVectorPtr blocks = ResourceGroupManager::getSingleton().findResourceNames("Level","*.cfg");
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOPRIGHT, "EditorSelectLbl", "Type de block :", 250);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->createLongSelectMenu(OgreBites::TL_TOPRIGHT, "ChatModeSelMenu", "Block", 200, 20, (*blocks));



}

void EditorState::itemSelected(OgreBites::SelectMenu* menu)
{

    m_currentBlock = menu->getSelectedItem();

    OgreFramework::getSingletonPtr()->m_pLog->logMessage("block selected :   "+m_currentBlock);
    /*
    switch(menu->getSelectionIndex())
    {
    case 0:
        break;

    }*/
}



void EditorState::buttonHit(OgreBites::Button *button)
{

    if(button->getName() == "RandomBtn")
    {
        // m_gameManager->getLevelMgrPtr()->clear();
        RandomMapGenerationParams genParam;
        genParam.size=28;
        genParam.pCentCrossable=0.75;
        m_gameManager->getLevelMgrPtr()->createRandomLevel(genParam);
    }






}
